package com.xxx.client.handler;

import com.xxx.client.registry.ChannelInfo;
import com.xxx.registry.ServerInfo;
import com.xxx.registry.ZkUtils;
import org.apache.curator.framework.CuratorFramework;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by louisyuu on 2020/4/30 上午10:17
 */
public class RemoteCallClient {


    /**
     * 可用的服务
     * <p>
     * key:127.0.0.1:8080#com.xxx.service.DemoService.demo
     */
    private final static Map<String, ChannelInfo> availableServers = new ConcurrentHashMap<>();


    private final static RemoteCallClient callClient = new RemoteCallClient();

    public static RemoteCallClient getInstance() {
        return callClient;
    }


    public Map<String, ChannelInfo> getAvailableServers() {
        return availableServers;
    }


    /**
     * 根据注册中心获取所有可用的available server list，并且创建针对各server端的client proxies
     *
     * @param serviceClass
     * @param targetMethodName
     * @return
     */
    public List<ChannelInfo> createProxies(final Class<?> serviceClass, final String targetMethodName) {

        List<ChannelInfo> clientProxies = new ArrayList<>();


        /**
         * 1.获取所有的server list
         */
        List<ServerInfo> serverList = getServerList();
        if (serverList.isEmpty()) {
            System.out.println("===================No servers found from zookeeper===================");
            return null;
        }


        /**
         * 2.创建Client proxy
         */
        serverList.forEach(server -> {
            createProxy(serviceClass, targetMethodName, server);
        });

        return clientProxies;
    }


    public void createProxy(final Class<?> serviceClass, final String targetMethodName, ServerInfo serverInfo) {

        ChannelInfo channelInfo = new ChannelInfo();
        channelInfo.setServerInfo(serverInfo);
        Object clientProxy = wrap(serviceClass, new RemoteCallHandler(serviceClass, targetMethodName, channelInfo));
        channelInfo.setClientProxy(clientProxy);
        availableServers.put(serverInfo.getServerAddress(), channelInfo);

    }


    public Object wrap(Class<?> serviceClass, InvocationHandler invocationHandler) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                , new Class<?>[]{serviceClass}
                , invocationHandler);

    }


    public static List<ServerInfo> getServerList() {
        List<ServerInfo> serverList = new ArrayList<>();
        try {
            CuratorFramework zkClient = ZkUtils.getZkClient();
            List<String> servers = zkClient.getChildren().forPath("/");
            for (String server : servers) {
                String[] serverAddress = server.split(":");
                ServerInfo serverInfo = new ServerInfo();
                serverInfo.setHost(serverAddress[0]);
                serverInfo.setPort(Integer.valueOf(serverAddress[1]));
                serverInfo.setServerAddress(server);
                serverInfo.setServerPath("/" + server);
                serverList.add(serverInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        return serverList;

    }
}
